﻿using System.Drawing;
using Core.Model.Blocks;
using Core.Model.Chunks;
using Core.Model.Types;
using Core.View.Builders;
using SlimDX.Direct3D10;
using SlimDX.Game.Model;

namespace SlimDX.Game.View.Builders
{
    public class SlimDxChunkBuilder : ChunkBuilder
    {
        private DataStream VertexStream;
        private DataStream IndexStream;
        private Device Device;

        public SlimDxChunkBuilder(Device device)
        {
            Device = device;
        }

        #region Overriden methods

        public override Chunk CreateChunk(VectorIndex index)
        {
            return new SlimDxChunk(index);
        }

        protected override void BeforeChunkBuild(Chunk chunk)
        {
            VertexStream = new DataStream(8 * Chunk.BlockCount * BlockVertex.BlockVertexSize, true, true);
            IndexStream = new DataStream(36 * Chunk.BlockCount * sizeof(int), true, true);
        }

        protected override void AddVertex(Chunk chunk, BlockFaceDirection faceDir, BlockType blockType, Vector3I blockPosition, Vector3I chunkRelativePosition, Vector3F vertexAdd, Vector3F normal, Vector2F uv1, byte sunLight, Color localLight)
        {
            base.AddVertex(chunk, faceDir, blockType, blockPosition, chunkRelativePosition, vertexAdd, normal, uv1, sunLight, localLight);

            if (faceDir != BlockFaceDirection.YIncreasing)
            {
                sunLight -= 2;

                if (sunLight < 0)
                {
                    sunLight = 0;
                }
            }

            //VertexStream.Write(new Vector4(chunkRelativePosition.X + vertexAdd.X, chunkRelativePosition.Y + vertexAdd.Y, chunkRelativePosition.Z + vertexAdd.Z, sunLight));
            VertexStream.WriteRange(new byte[]
                                        {
                                            (byte) (chunkRelativePosition.X + vertexAdd.X),
                                            (byte) (chunkRelativePosition.Y + vertexAdd.Y),
                                            (byte) (chunkRelativePosition.Z + vertexAdd.Z),
                                            sunLight
                                        });
            
            //VertexStream.Write(new Vector4(255.0f, 0.0f, 0.0f, 1.0f));
            VertexStream.WriteRange(new float[] {uv1.X, uv1.Y});
        }

        protected override void AddIndex(Chunk chunk, BlockType blockType, short i1, short i2, short i3, short i4, short i5, short i6)
        {
            base.AddIndex(chunk, blockType, i1, i2, i3, i4, i5, i6);

            int vertexCount = (int)(VertexStream.Position / BlockVertex.BlockVertexSize) - 4;

            IndexStream.Write((int)(vertexCount + i1));
            IndexStream.Write((int)(vertexCount + i2));
            IndexStream.Write((int)(vertexCount + i3));
            IndexStream.Write((int)(vertexCount + i4));
            IndexStream.Write((int)(vertexCount + i5));
            IndexStream.Write((int)(vertexCount + i6));
        }

        protected override void AfterChunkBuild(Chunk chunk)
        {
            // Before create buffer

            int vertexSizeInBytes = (int)VertexStream.Position;
            int indexSizeInBytes = (int)IndexStream.Position;

            int vertexCount = (int)(VertexStream.Position / BlockVertex.BlockVertexSize);
            int indexCount = (int)IndexStream.Position / sizeof(int);

            VertexStream.Position = 0;
            IndexStream.Position = 0;

            SlimDxChunk slimDxChunk = (SlimDxChunk)chunk;

            slimDxChunk.VertexBuffer = new Buffer(Device, VertexStream, new BufferDescription()
            {
                BindFlags = BindFlags.VertexBuffer,
                CpuAccessFlags = CpuAccessFlags.None,
                OptionFlags = ResourceOptionFlags.None,
                SizeInBytes = vertexSizeInBytes,
                Usage = ResourceUsage.Default
            });

            slimDxChunk.IndexBuffer = new Buffer(Device, IndexStream, new BufferDescription()
            {
                BindFlags = BindFlags.IndexBuffer,
                CpuAccessFlags = CpuAccessFlags.None,
                OptionFlags = ResourceOptionFlags.None,
                SizeInBytes = indexSizeInBytes,
                Usage = ResourceUsage.Default
            });

            chunk.VertexCount = vertexCount;
            chunk.IndexCount = indexCount;
            chunk.PrimitivesCount = indexCount/3;

            chunk.IsReady = true;

            VertexStream.Dispose();
            IndexStream.Dispose();

            VertexStream = null;
            IndexStream = null;
        }

        #endregion
    }
}
